#!/usr/bin/env python
#coding=utf-8
from django import template
from django.template.defaulttags import url
from django.template.defaultfilters import stringfilter

import re

register = template.Library()

##TEMPLATE_POST_PAGE_HREF=r'''?q=%s&page=%d'''
##TEMPLATE_POST_PAGE_FIRST=r'''<a align=center href="%s" type=submit>[first]</a>'''%TEMPLATE_POST_PAGE_HREF
##TEMPLATE_POST_PAGE_AFT_FIRST=r'''<a align=center href="%s" type=submit>[<%d]</a>'''%TEMPLATE_POST_PAGE_HREF
##TEMPLATE_POST_PAGE_BFE_LAST=r'''<a align=center href="%s" type=submit>[>%d]</a>'''%TEMPLATE_POST_PAGE_HREF
##TEMPLATE_POST_PAGE_LAST=r'''<a align=center href="%s" type=submit>[last]</a>'''%TEMPLATE_POST_PAGE_HREF
##
##TEMPLATE_REPLY_PAGE_HREF=r'''{%% url post-url post_id=%d page_from=%d %%}'''
##TEMPLATE_REPLY_PAGE_FIRST=r'''<a align=center href="%s" type=submit>[[1]]</a>'''%TEMPLATE_REPLY_PAGE_HREF
##TEMPLATE_REPLY_PAGE_AFT_FIRST=r'''<a align=center href="%s" type=submit>[<%d]</a>'''%TEMPLATE_REPLY_PAGE_HREF
##TEMPLATE_REPLY_PAGE_BFE_LAST=r'''<a align=center href="%s" type=submit>[>%d]</a>'''%TEMPLATE_REPLY_PAGE_HREF
##TEMPLATE_REPLY_PAGE_LAST=r'''<a align=center href="%s" type=submit>[[%d]]</a>'''%TEMPLATE_REPLY_PAGE_HREF
pimg_full = re.compile(r'(<img.*?\s+src\s*=\s*"\s*(?!"))(.+?)(\s*".*?/>)', re.U|re.M|re.S|re.I)
pimg_related = re.compile(r'(<img.*?\s+src\s*=\s*"\s*(?!https?:|"))(.+?)(\s*".*?/>)', re.U|re.M|re.S|re.I)
pa = re.compile(r'(<a.*?href\s*=\s*"\s*(?!mailto:|#|https?:|"))(.+?)(\s*".*?>.*?</a>)', re.U|re.M|re.S|re.I)
paimg = re.compile(r'(<a.*?href\s*=\s*"\s*(?!mailto:|#"))(.+?)(\s*".*?>\s*<img.*?/>\s*</a>)', re.U|re.M|re.S|re.I)

class ItemFromListNode(template.Node):
	u'''将 lst[idex] 做为名为 var_name 的变量放入 context, 如果var_name为空则作为函数返回'''
	def __init__(self, lst, idx, var_name):
		self.lst = template.Variable(lst)
		self.idx = template.Variable(idx)
		self.var_name = var_name

	def render(self, context):
		try:
			act_list = self.lst.resolve(context)
			act_idx = self.idx.resolve(context)
			if isinstance(act_list, list):
				if act_idx < len(act_list):
					if self.var_name:
						context[self.var_name] = act_list[act_idx]
						return ''
					else:
						return act_list[act_idx]
		except template.VariableDoesNotExist:
			return ''

		return ''

@register.tag(name='ListItemByIndex')
def tagGetItemFromList(parser, token):
	try:
		tag_name, arg = token.contents.split(None, 1)
	except ValueError:
		raise template.TemplateSyntaxError,'%s tag requires exactly two arguments (list and index)' % token.contents.split()[0]

#	m = re.search(r'(.*?) \s*(.*?) \s*as (\w+)\s*', arg)
	m = re.search(r'\s*(.*?)\s+(.*?)\s+(?:as)?\s+(\w+)?', arg) # 支持as不存在的情况
	if not m:
		raise template.TemplateSyntaxError('%s tag had invalid arguments' % tag_name)
	lst, idx, var_name = m.groups()

	return ItemFromListNode(lst, idx, var_name)


class Items4PostListUrlPages(template.Node):
	u'''输出主题列表中 cur_page 前后10 页的链接 和首页尾页的链接'''
	def __init__(self, q, cur_page, max_page, var_name):
		self.q = template.Variable(q)
		self.cur_page = template.Variable(cur_page)
		self.max_page = template.Variable(max_page)
		self.var_name = var_name
		self.show_page = 10

	def render(self, context):
		if self.var_name:
			v = context.get(self.var_name, None)
			if v:
				print('already have %s,just use it~'%(self.var_name,))
				return v

		try:
			q = self.q.resolve(context)
			cur_pg = self.cur_page.resolve(context)
			max_pg = self.max_page.resolve(context)
			print('q=%s,cur_pg=%d,max_pg=%d'%(q, cur_pg, max_pg))
			ol = []
			if cur_pg > 1:
				ol.append('<a align=center href="?%s&page=1" type=submit>[first]</a>'%q)
				tmp = 0
				for pg in range(2 if cur_pg-self.show_page < 2 else cur_pg-self.show_page,
												3 if cur_pg-1 < 2 else cur_pg):
					if pg == cur_pg: continue
					ol.append('<a align=center href="?%s&page=%d" type=submit>[<%d]</a>'%(q, pg, pg))
					if tmp == 0: tmp = pg
##				print('<tmp=%d'%(tmp,))
				if tmp-1 > 1:
					ol.insert(1,'[...]')
			ol.append('<b>%d</b>'%cur_pg)
			if cur_pg < max_pg:
				tmp = max_pg
				for pg in range(max_pg-1 if cur_pg+1 > max_pg-1 else cur_pg+1,
													max_pg if cur_pg+self.show_page > max_pg-1 else cur_pg+self.show_page+1):
					if pg == cur_pg: continue
					ol.append('<a align=center href="?%s&page=%d" type=submit>[>%d]</a>'%(q, pg, pg))
					tmp = pg
##				print('>tmp=%d'%(tmp,))
				if tmp+1 < max_pg:
					ol.append('[...]')
				ol.append('<a align=center href="?%s&page=%d" type=submit>[last]</a>'%(q, max_pg))

			t = '&nbsp;'.join(ol)
			if self.var_name:
				context[self.var_name] = t
			return t
		except template.VariableDoesNotExist:
			return ''

@register.tag(name='PostListUrlPages')
def filterOutputPostListUrlPages(parser, token):
	try:
		tag_name, arg = token.contents.split(None, 1)
	except ValueError:
		raise template.TemplateSyntaxError,'%s tag requires 3 arguments (search_word,cur_page and max_page)' % token.contents.split()[0]

##	m=re.search('\s*(.*?)\s+(.*?)\s+(\w+)\s*',arg)
	m = re.search('\s*(\w+)\s+(\w+)\s+(\w+)(?:\s+as\s+)?(\w+)?\s*', arg)
	if not m:
		raise template.TemplateSyntaxError('%s tag had invalid arguments' % tag_name)
	q, cur_page, max_page, var_name = m.groups()
##	print('arg=%s'%(arg,))
##	print('token.contents=%s,q=%s,cur_page=%s,max_page=%s'%(token.contents,q,cur_page,max_page))
	return Items4PostListUrlPages(q, cur_page, max_page, var_name)





class Items4ReplyListUrlPages(template.Node):
	u'''输出回帖列表中 cur_page 前后10 页的链接 和首页尾页的链接'''
	def __init__(self, parser, p, cur_page, max_page, var_name):
		self.parser = parser
		self.p = template.Variable(p)
		self.cur_page = template.Variable(cur_page)
		self.max_page = template.Variable(max_page)
		self.var_name = var_name
		self.show_page = 10

	def render(self, context):
		if self.var_name:
			v = context.get(self.var_name, None)
			if v:
				print('already have %s,just use it~'%(self.var_name,))
				return v

		try:
			p = self.p.resolve(context)
			cur_pg = self.cur_page.resolve(context)
			max_pg = self.max_page.resolve(context)
			ol = []

			if cur_pg > 1:
				ol.append('<a align=center href="{%% url post-url post_id=%d page_from=1 %%}" type=submit>[[1]]</a>'%(p.id,))
				tmp = 0
				for pg in range(2 if cur_pg-self.show_page < 2 else cur_pg-self.show_page,
												3 if cur_pg-1 < 2 else cur_pg):
					if pg == cur_pg: continue
					ol.append('<a align=center href="{%% url post-url post_id=%d page_from=%d %%}" type=submit>[<%d]</a>'%(p.id, pg, pg))
					if tmp == 0: tmp = pg
##				print('<tmp=%d'%(tmp,))
				if tmp-1 > 1:
					ol.insert(1,'[...]')
			ol.append('<b>%d</b>'%cur_pg)
			if cur_pg < max_pg:
				tmp = max_pg
				for pg in range(max_pg-1 if cur_pg+1 > max_pg-1 else cur_pg+1,
													max_pg if cur_pg+self.show_page > max_pg-1 else cur_pg+self.show_page+1):
					if pg == cur_pg: continue
					ol.append('<a align=center href="{%% url post-url post_id=%d page_from=%d %%}" type=submit>[>%d]</a>'%(p.id, pg, pg))
					tmp = pg
##				print('>tmp=%d'%(tmp,))
				if tmp +1 < max_pg:
					ol.append('[...]')
				ol.append('<a align=center href="{%% url post-url post_id=%d page_from=%d %%}" type=submit>[[%d]]</a>'%(p.id, max_pg, max_pg))

			# 因为包含 tag url 所以要再次调用模版处理之
			t = template.Template('&nbsp;'.join(ol)).render(context)
			if self.var_name:
				context[self.var_name] = t
			return t

		except template.VariableDoesNotExist:
			return ''

@register.tag(name='ReplyListUrlPages')
def filterOutputReplyListUrlPages(parser, token):
	try:
		tag_name, arg = token.contents.split(None, 1)
	except ValueError:
		raise template.TemplateSyntaxError,'%s tag requires 3 arguments (search_word,cur_page and max_page)' % token.contents.split()[0]

##	print('arg=%s'%(arg,))
##	m=re.search('\s*(.*?)\s+(.*?)\s+(\w+)\s*',arg)
	m = re.search('\s*(\w+)\s+(\w+)\s+(\w+)(?:\s+as\s+)?(\w+)?\s*', arg)
	if not m:
		raise template.TemplateSyntaxError('%s tag had invalid arguments' % tag_name)
	p, cur_page, max_page, var_name = m.groups()
##	print('token.contents=%s,p=%s,cur_page=%s,max_page=%s,varname=%s'%(token.contents,p,cur_page,max_page,var_name))
	return Items4ReplyListUrlPages(parser, p, cur_page, max_page, var_name)


from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe

# should not use this filter, use tag ProcessUrl  instead.
@register.filter(name='ProcessRelateUrl')
@stringfilter
def filterOutputProcessRelateUrl(value, arg, autoescape=None):
	u'''将网页里面的相对链接补全为绝对链接，base url 为 arg.
	不处理 mailto，本页锚链接，空链接
	'''
##	print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')
	if autoescape:
		esc = conditional_escape
	else:
		esc = lambda x:x
##	print ('base url=%s'%(arg,))
	# related url ==> absolute url
	imglist = pimg_related.findall(value)
	if imglist:
		print('find %d img url'%(len(imglist),))
		for i, x in enumerate(imglist):
			print('%d) %s'%(i+1, x[1]))
		value = pimg_related.sub('\g<1>%s\g<2>\g<3>'%(esc(arg),), value)
	# (absolute url) ==> url img-url x
	imglist = pimg_full.findall(value)
	if imglist:
		value = pimg_full.sub('\g<1>%s\g<2>/\g<3>'%('/getpost/pic/',), value) # TODO: hard code, the function should be wrote as tag later!!!

	alist = pa.findall(value)
	if alist:
		print('find %d a url'%(len(alist),))
		for i, x in enumerate(alist):
			print('%d) %s'%(i+1, x[1]))
		value = pa.sub('\g<1>%s\g<2>\g<3>'%(esc(arg),), value)
##	print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n')
	return mark_safe(value)
filterOutputProcessRelateUrl.needs_autoescape = True


@register.filter(name='HighlightWord')
@stringfilter
def filterOutputHighlightWord(value, arg, autoescape=None):
	u'''高亮指定的关键字：将value中的arg替换为<font color="red">arg</font>
	只支持单个关键字
	'''
##	print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')
##	print ('keyword=%s'%(arg,))
	if arg:
		if autoescape:
##			print('autoescape!')
			esc = conditional_escape
		else:
			esc = lambda x:x
		value = esc(value).replace(arg, ''.join(('<font color="red">', arg, '</font>')))
##	print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n')
	return mark_safe(value)
filterOutputHighlightWord.needs_autoescape = True







@register.tag(name='HighlightWords')
def tagHighlightWords(parser, token):
	try:
		tag_name, arg = token.contents.split(None, 1)
	except ValueError:
		raise template.TemplateSyntaxError,'%s tag requires 2 arguments (@string,@words with keys seperated with space)' % token.contents.split()[0]

	m = re.search('(?iLsu)\s*(.+?)\s+(.+?)(?:\s+as\s+)?(\w+)?\s*',arg)
	if not m:
		raise template.TemplateSyntaxError('%s tag had invalid arguments' % tag_name)
	s, words, var_name = m.groups()
##	print('arg=%s,s=%s,words=%s,varname=%s'%(arg,s,words,var_name))
	return HightlightWords(parser, s, words, var_name)


class HightlightWords(template.Node):
	u'''高亮指定的关键字：将关键字arg替换为<font color="red">arg</font>
	支持多个关键字，各关键字之间用空格分割
	'''
	def __init__(self, parser, s, words, var_name):
		self.parser = parser
		self.s = template.Variable(s)
		self.words = template.Variable(words)
		self.var_name = var_name

	def render(self, context):
		if self.var_name:
			v = context.get(self.var_name, None)
			if v:
				print('already have %s,just use it~'%(self.var_name,))
				return v

		try:
			s = self.s.resolve(context)
			words = self.words.resolve(context)

			sl=words.strip().split()
			sl.sort(key=lambda x:len(x),reverse=True)
			for k in sl:
				if not k.startswith('-'):
					s = s.replace(k, ''.join(('<font color="red">', k, '</font>')))

			if self.var_name:
				context[self.var_name] = s
			return s

		except template.VariableDoesNotExist:
			return ''







@register.tag(name='ProcessUrl')
def tagProcessUrl(parser, token):
	try:
		tag_name, arg = token.contents.split(None, 1)
	except ValueError:
		raise template.TemplateSyntaxError,'%s tag requires 2 arguments (@text,@baseurl)' % token.contents.split()[0]

	m = re.search('(?iLsu)\s*(\S+)\s+(\S+)(?:\s+as\s+)?(\S+)?\s*',arg)
	if not m:
		raise template.TemplateSyntaxError('%s tag had invalid arguments' % tag_name)
	content, baseurl, var_name = m.groups()
##	print('arg=%s,content=%s,baseurl=%s,varname=%s'%(arg,content,baseurl,var_name))
	return ProcessUrl(parser, content, baseurl, var_name)


class ProcessUrl(template.Node):
	u'''将网页里面的相对链接补全为绝对链接，base url 为 arg.
	不处理 mailto，本页锚链接，空链接
	'''
	def __init__(self, parser, content, baseurl, var_name):
		self.parser = parser
		self.content = template.Variable(content)
		self.baseurl = template.Variable(baseurl)
		self.var_name = var_name

	def render(self, context):
		if self.var_name:
			v = context.get(self.var_name, None)
			if v:
				print('already have %s,just use it~'%(self.var_name,))
				return v

		try:
			content = self.content.resolve(context)
			baseurl = self.baseurl.resolve(context)
##			print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n')
##			print ('base url=%s'%(baseurl,))
##			print context
##			s='{% url img-url url="http://some.com/test.jpg" %}'
##			t=template.Template(s).render(context)
##			print t

			# related url ==> absolute url
			imglist = pimg_related.findall(content)
			if imglist:
				print('find %d img url'%(len(imglist),))
				for i, x in enumerate(imglist):
					print('%d) %s'%(i+1, x[1]))
				content = pimg_related.sub('\g<1>%s\g<2>\g<3>'%(baseurl,), content)

			# (absolute url) ==> url img-url x
			imglist = pimg_full.findall(content)
			if imglist:
				content = pimg_full.sub('\g<1>{% url img-url url="\g<2>" %}\g<3>', content)
##				print '%s'%content
##			content = template.Template(content).render(context)

			# (a url) ==> url img-url x
			alist = pa.findall(content)
			if alist:
				print('find %d a url'%(len(alist),))
				for i, x in enumerate(alist):
					print('%d) %s'%(i+1, x[1]))
				content = pa.sub('\g<1>{% url img-url url="\g<2>" %}\g<3>', content)

			# (a img url) ==> url img-url x
			alist=paimg.findall(content)
			if alist:
				content = paimg.sub('\g<1>{% url img-url url="\g<2>" %}\g<3>', content)

##			print '\nbefore render:%s'%content

			t = template.Template(content).render(context)
##			print '\nafter render:%s'%t
			if self.var_name:
				context[self.var_name] = t
##			print ('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n')
			return t
		except template.VariableDoesNotExist:
			return ''







